const { ccclass, property, menu, disallowMultiple } = cc._decorator;
/**
 *  数据方向 
 */
enum Direction {
    Up = -1,
    Down = 1,
}
/**
* scroolView 辅助工具 父类
*/
@ccclass

export default class ScrollViewToolParent extends cc.Component {
    @property(cc.ScrollView)
    scrollview: cc.ScrollView = null;
    @property(cc.Prefab)
    itemPrefab: cc.Prefab = null;

    @property({
        displayName: "预加载子节点个数",
        tooltip: "预加载个数,超出屏幕没显示出来的个数"
    })
    perLoad: number = 3;
    @property({
        displayName: "检测敏感度(像素)",
        tooltip: "检测敏感度,移动多少个像素检测一次"
    })
    detectionThreshold: number = 10;
    @property({
        displayName: "数据延展方向",
        tooltip: "数据延展的方向 :\nDown-新的数据加在下方 \nUp-新的数据加在上方",
        type: cc.Enum(Direction),
    })
    direction: Direction = Direction.Down



    _content: cc.Node = null;
    _layout: cc.Layout = null;
    _node_pool: cc.NodePool = null;


    /** 子项赋值回调 */
    _callback: (node: cc.Node, index: number, isDynamic: boolean) => void = null; //
    /** 继续查询回调 */
    _continueQueryCallback: (index: number, refreshDataCountCallback: (dataCount: number) => void) => void = null;
    /** 是否动态添加,逻辑上如果数据量不足以把scrollView装满的话,那么 _is_auto_add = false ,但此处为分页,所以总为true (暂不删除此字段,等待优化)*/
    _is_auto_add: boolean = true;
    /** 当前数据个数 */
    _dataCount = 0;
    /** 子节点是否在_callback中初始化 */
    _itemIsInitByCallBack = false;
    /** 上一次移动的Y坐标 */
    _lastMoveY: number = 0;
    /** 子项数组 */
    _itemArray: cc.Node[];
    /** 以使用了的最大index记录 */
    _indexMaxMark = -1
    /** 没有在查询中 */
    _notQuerying

    _dir

    onLoad() {
        if (this._content) {
            return
        }

        this._dir = this.direction == Direction.Down ? 1 : -1
        this._node_pool = new cc.NodePool();
        this._itemArray = [];
        this._content = this.scrollview.content


        this._setupWidget()
        this._setupLayout()
        this._lastMoveY = this._content.y

    }
    onEnable() {
        this._onScrollEvent()

    }
    onDisable() {
        this._offScrollEvent()
    }


    /** 设置约束 */
    _setupWidget() {

        let widget = this._content.getComponent(cc.Widget)
        if (!widget) {
            return
        }

        widget.isAlignLeft = true
        widget.left = 0
        widget.isAlignRight = true
        widget.right = 0
        if (this._dir == Direction.Down) {

            widget.isAlignTop = true
            widget.top = 0
            widget.isAlignBottom = false
        } else {
            widget.isAlignTop = false
            widget.isAlignBottom = true
            widget.bottom = 0

        }
    }

    /** 设置布局 */
    _setupLayout() {
        this._layout = this._content.getComponent(cc.Layout)
        if (!this._layout) {
            this._layout = new cc.Layout();
            this._layout.spacingY = 0;
            return
        }
        // 不建议使用padding
        // this._layout.paddingTop = 0;
        // this._layout.paddingBottom = 0;
        // this._layout.paddingLeft = 0;
        // this._layout.paddingRight = 0;
        // 注销节点上的布局，方便后面手动排版
        this._layout.enabled = false
        this._layout.resizeMode = cc.Layout.ResizeMode.NONE

    }

    setFirstInCenter() {
        let itemHeight = this.itemPrefab.data.height;
        let contentParentHeight = this._content.parent.height;
        this._layout.paddingBottom = this._layout.paddingTop = (contentParentHeight - itemHeight) / 2
    }

    setDataByIndex(index = 0, maxIndex = 0) {
        index = index < 0 ? 0 : index
        let len = this._content.childrenCount
        let firstItem = this._itemArray[0]
        let lastItem = this._itemArray[len - 1]
        if (index <= lastItem.index && index >= firstItem.index) {
            //这个节点已经被创建出来了
            return;
        }
        let startIndex = Math.floor(index - (len - this.perLoad) / 2)
        startIndex = startIndex > maxIndex - len + 1 ? maxIndex - len + 1 : startIndex
        startIndex = startIndex < 0 ? 0 : startIndex
        cc.log("startIndex", startIndex)
        //用於跳轉某個數據點時使用

        let y = this._content.y
        this._content.height = 0 + this._layout.paddingTop + this._layout.paddingBottom
        /** 子项数组 */
        this._itemArray = []
        this._indexMaxMark = -1;
        for (let i = 0; i < len; i++) {
            let node = this._content.children[i]
            if (this._dir == Direction.Down) {
                this._itemArray.push(node);
            } else {
                this._itemArray.unshift(node);
            }
        }
        for (let i = 0; i < startIndex; i++) {
            this._refreshContentHeight(this.itemPrefab.data, i)
        }



        this._refreshUnUseChildData(true, startIndex)
        this._content.y = y;

    }
    /** 初始化所有子项 */
    _initAllItem() {

        if (!this._content) {
            this.onLoad()
        }
        /** 总是需要添加数据  */
        this._is_auto_add = true
        /** 初始化 */

        let len = this._content.children.length;
        for (let i = len - 1; i >= 0; i--) {
            let child = this._content.children[i];
            if (child) {
                this._put(child)
            }
        }
        this._content.height = 0 + this._layout.paddingTop + this._layout.paddingBottom
        this._content.y = 0
        /** 需要的子项数量  一页显示的+预加载的 */
        let need_count = 0
        need_count = Math.ceil((this._content.parent.height) / (this.itemPrefab.data.height + this._layout.spacingY)) + this.perLoad;

        /** 子项数组 */
        this._itemArray = []
        this._indexMaxMark = -1;


        for (let index = 0; index < need_count; index++) {
            let node = this._getCanUsedItem()
            node.parent = this._content
            node.active = false;
            node.index = index;
            if (this._dir == Direction.Down) {

                this._itemArray.push(node);
            } else {
                this._itemArray.unshift(node);
            }
        }


    }

    /** 刷新Content的高度
     * 
     * @param node 
     * @param index 
     */
    _refreshContentHeight(node, index) {
        if (index > this._indexMaxMark) {
            this._indexMaxMark = index;
            this._content.height += node.height + this._layout.spacingY
        }
    }

    /** 获取新的数据
     * 
     * @param index 当前index值
     * @override
     */
    _getNewData(index, isTop = false) {
        cc.log("獲取新的數據 parent")
    }
    /** 一页数据不足已将预创建的节点都赋值时使用(因为这个时候不能滑动,也就不能触发滑动的更新数据)
     *  更新数据
     * @param reset 重置
     */
    _refreshUnUseChildData(reset = true, startIndex = 0) {

        for (let index = 0; index < this._content.childrenCount && (index + startIndex) < this._dataCount; index++) {
            if (this._callback) {
                let node = this._content.children[index]
                if (node.active && !reset) continue;//跳过已经赋值的节点
                node.active = true;
                node.index = (index + startIndex);
                this._callback(node, (index + startIndex), false)
                let y = -(this._content.height + node.height / 2) * this._dir

                if (this._dir == Direction.Down) {
                    y += this._layout.paddingBottom
                } else {
                    y += this._layout.paddingTop
                }
                node.y = y
                this._refreshContentHeight(node, (index + startIndex))
                this._getNewData((index + startIndex))
            } else {
                break;
            }
        }

    }

    /**取消滑动监听 */
    _offScrollEvent() {
        this.scrollview.node.off('scrolling', this._ScrollEvent, this)
    }

    /** 注册滑动监听 */
    _onScrollEvent() {
        this.scrollview.node.on('scrolling', this._ScrollEvent, this)
    }

    /** 滑动事件 */
    _ScrollEvent(event) {
        let offset = this.detectionThreshold || 1 //每移动多少像素检测一次
        if (this._is_auto_add) {
            // 动态加载
            let chazhi = this._lastMoveY - this._content.y
            if (chazhi > offset) {//下滑

                // 计算最下面一个是否移出视图
                let bottom = this._getBottomItem()
                if (!bottom) return;
                //将View坐标 转换到content层进行比较
                let view = this._content.parent;
                let a = view.convertToWorldSpaceAR(cc.v2())
                let b = this._content.convertToNodeSpaceAR(a)
                // (b.y < -(this._content.parent.height + bottom.height / 2) && this._dir == Direction.Down) || (b.y < -(bottom.height / 2) && this._dir == Direction.Up)
                if (((bottom.y + bottom.height / 2) < (b.y - view.height * (view.anchorY)))) {
                    // cc.log("下滑")
                    let top = this._getTopItem()
                    let topZorder = top.index;

                    if (topZorder <= 0) {
                        return
                    }
                    if (topZorder >= this._dataCount - 1) {
                        return
                    }
                    let order = topZorder - 1 * this._dir
                    //最下面的结点删掉
                    bottom = this._itemArray.pop();//
                    let node
                    //如果这个节点没有执行初始化,那么干掉这个重新创建一个新的
                    if (!this._itemIsInitByCallBack) {
                        this._put(bottom)
                        //创建一个节点 放在最上面
                        node = this._getCanUsedItem();
                        node.parent = this._content;
                    } else {
                        node = bottom
                    }
                    if (this._callback) {
                        this._callback(node, order, true);
                        this._refreshContentHeight(node, order)
                        this._getNewData(order, true)
                    }

                    node.y = top.y + this._layout.spacingY + node.height / 2 + top.height / 2
                    node.index = order;
                    this._itemArray.unshift(node);
                }
                this._lastMoveY = this._content.y
            } else if (chazhi < -offset) {//上滑
                // 计算最上面一个是否移出视图
                let top = this._getTopItem()
                if (!top) return;

                //将View坐标 转换到content层进行比较
                let view = this._content.parent;
                let a = view.convertToWorldSpaceAR(cc.v2())
                let b = this._content.convertToNodeSpaceAR(a)
                if ((top.y - top.height / 2) > (b.y + view.height * (1 - view.anchorY))) {
                    // cc.log("上滑")
                    let bottom = this._getBottomItem()
                    let bottomOrder = bottom.index;
                    if (bottomOrder <= 0) {
                        return
                    }
                    if (bottomOrder >= this._dataCount - 1) {
                        return
                    }
                    let order = bottomOrder + 1 * this._dir
                    //最上面的结点删掉
                    top = this._itemArray.shift()
                    let node
                    //如果这个节点没有执行初始化,那么干掉这个重新创建一个新的
                    if (!this._itemIsInitByCallBack) {
                        this._put(top)
                        //创建一个节点 放在最上面
                        node = this._getCanUsedItem();
                        node.parent = this._content;
                    } else {
                        node = top
                    }

                    if (this._callback) {
                        this._callback(node, order, true);
                        this._refreshContentHeight(node, order)
                        this._getNewData(order)
                    }
                    node.y = bottom.y - this._layout.spacingY - node.height / 2 - bottom.height / 2
                    node.index = order;
                    this._itemArray.push(node);
                }
                this._lastMoveY = this._content.y
            }
        }
    }

    /** 取当前最上节点 */
    _getTopItem() {
        return this._itemArray[0];
    }

    /** 取当前最下节点 */
    _getBottomItem() {
        return this._itemArray[this._itemArray.length - 1];
    }

    /**没有父节点的子节点 */
    _getCanUsedItem() {
        if (this._node_pool.size() > 0) {
            cc.log("节点池 -> 取节点")
            return this._node_pool.get();
        } else {
            cc.log("节点池 -> 生成节点")
            return cc.instantiate(this.itemPrefab);
        }
    }

    /** 回收节点 */
    _put(node) {
        this._node_pool.put(node);
    }

}